package com.smartfast4j.netty.echoclient;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

/**
 *
 * 如同服务器，客户端也要至少拥有一个用来处理数据的ChannelInboundHandler。
 * 通过ChannelHandler实现客户端逻辑，一般选择从SimpleChannelInboundHandler 类继承，然后重写下面的方法：
     channelActive()——在到服务器的连接已经建立之后将被调用；
     channelRead0()——当从服务器接收到一条消息时被调用；
     exceptionCaught()——在处理过程中引发异常时被调用
 */
@Sharable//标记该类的实例可以被多个Channel共享
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    /**
     * 重写了channelActive()方法，其将在一个连接建立时被调用。这确保了数据将会被尽可能快地写入服务器
     * @param ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("EchoClientHandler→channelActive(在到服务器的连接已经建立之后将被调用)");
        //当被通知Channel是活跃的时候，向服务端发送一条消息
        String msg = "如同服务器，客户端也要至少拥有一个用来处理数据的ChannelInboundHandler。\n" +
                " * 通过ChannelHandler实现客户端逻辑，一般选择从SimpleChannelInboundHandler 类继承，然后重写下面的方法：\n" +
                "     channelActive()——在到服务器的连接已经建立之后将被调用；\n" +
                "     channelRead0()——当从服务器接收到一条消息时被调用；\n" +
                "     exceptionCaught()——在处理过程中引发异常时被调用";
        //ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
        ctx.writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
    }

    /**
     * 每当接收从服务端发送过来的数据时，都会调用这个方法。
     * 需要注意的是，由服务器发送的消息可能会被分块接收。也就是说，如果服务器发送5字节，那么不能保证这 5 字节会被一次性接收。
     * 即使是对于这么少量的数据，channelRead0()方法也可能会被调用两次，第一次使用一个持有3字节的 ByteBuf（Netty 的字节容器），第二次使用一个持有 2 字节的 ByteBuf。
     * 作为一个面向流的协议，TCP 保证了字节数组将会按照服务器发送它们的顺序被接收。
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {
        System.out.println("EchoClientHandler→channelRead0(当从服务器接收到一条消息时被调用)");
        System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("EchoClientHandler→exceptionCaught(在处理过程中引发异常时被调用。)");
        cause.printStackTrace();
        ctx.close();
    }
}
